/*!
 * @description
 * Плагин, дополняющий текстовое поля удобным для введения ключевых слов функционалом.
 * @requires jQuery 1.3.2 (http://www.jquery.com/)
 * @author Dmitry Shkinev (berkel@yandex.ru)
 * @link http://code.google.com/p/itags/
 * @version 0.1.0
 */

/**
 *
 * @param {HTMLTextAreaElement} input
 * @param {Object} options
 */
jQuery.itags = function(input, options)
{
	var _options = $.extend({}, jQuery.fn.itags.defaultOptions, options),

		_$input = $(input);

		if (0 === _$input.length)
		{
			return _$input;
		}

		_$input.bind('tagadd tagremove', function()
			{
				$(this).val(_tags.join(_options.tag_separator));
			})
			.focus(onInputFocus);

	var _$holder = $('<input type="text"/>')
			.focus(onHolderFocus)
			.blur(onHolderBlur),

		_$container = $('<div class="itags-holder-container"></div>')
			.css({
				'width': (input.offsetWidth - 2) + 'px',
				'height': (input.offsetHeight - 2) + 'px'
			})
			.click(onInputFocus)
			.append(
				$('<ul class="itags-holder"></ul>')
					.append($('<li class="itags-input"></li>')
					.append(_$holder))
			),

		_$hintDefault = $('<li class="itags-default">' + _options.tag_hint + '</li>'),

		_$hintContainer = $('<ul class="itags-ajutor"></ul>')
			.append(_$hintDefault),

		_tags = [];

	$(window).resize(function()
	{
		updateUlPosition();
		updateAjutorPosition();
	});

	updateUlPosition();

	var inputValue = _$input.val();
	if (inputValue)
	{
		_$input.val('');

		var tags = inputValue.split(_options.tag_separator_pattern);

		for (var tag, i = 0, l = tags.length; i<l; i++)
		{
			tag = $.trim(tags[i]);

			if (tag)
			{
				addTag(tag);
			}
		}

		if (_tags.length)
		{
			_$container.appendTo(document.body);
		}
	}

	function addTag(tag)
	{
		$('<li class="itags-box">' + tag + '</li>')
			.click(function()
			{
				var $node = $(this);
				if ($node.hasClass('selected'))
				{
					$node.removeClass('selected');
				}
				else
				{
					$node.addClass('selected');
				}
			})
			.hover(addOverClass, removeOverClass)
			.append(

				$('<a class="itags-close" href="javascript:void(0);">&#215;</a>')
					.click(function(evt)
					{
						removeTagByIndex($(this).parent().prevAll().length);
						evt.preventDefault();
					})
				)

			.insertBefore($('li:last', _$container));

		_tags.push(tag);

		_$input.triggerHandler('tagadd', tag);
	}

	function removeTagByIndex(index)
	{
		var tag = _tags[index];
		if (tag)
		{
			$('li', _$container).eq(index).remove();
			_tags.splice(index, 1);
			_$input.triggerHandler('tagremove', tag);
		}
	}

	function updateAjutorPosition()
	{
		var offset = _$input.offset(), inputHeight = _$input.get(0).offsetHeight;
		_$hintContainer.css({
			'left': offset.left + 'px',
			'top': (offset.top + inputHeight) + 'px'
		});
	}

	function updateUlPosition()
	{
		var offset = _$input.offset();
		_$container.css({
			'left': offset.left + 'px',
			'top': offset.top + 'px'
		});
	}

	function onInputFocus()
	{
		_$holder.focus();
	}

	function onHolderFocus(evt)
	{
		if (document.body !== _$container.parent().get(0))
		{
			_$container.appendTo(document.body);
		}

		if (document.body !== _$hintContainer.parent().get(0))
		{
			_$hintContainer.appendTo(document.body);
		}

		$('li.itags-item', _$hintContainer).remove();

		updateUlPosition();
		updateAjutorPosition();

		_$hintDefault.show();
		_$hintContainer.show();

		_$holder
			.bind('keydown', onHolderKeyDown)
			.bind('keyup', onHolderKeyUp);

		onHolderKeyUp(evt);
	}

	function onHolderBlur()
	{
		_$hintDefault.hide();
		_$hintContainer.hide();

		_$holder
			.unbind('keydown', onHolderKeyDown)
			.unbind('keyup', onHolderKeyUp);
	}

	function onHolderKeyDown(evt)
	{
		if (8 === evt.keyCode && '' === _$holder.val() && _tags.length) // BackSpace
		{
			removeTagByIndex(_tags.length - 1);

			evt.preventDefault();
			evt.stopPropagation();
		}
		else if (46 === evt.keyCode && _tags.length) // Delete
		{
			var $li = $('li.selected', _$container);

			if ($li.length)
			{
				$li = $('li', _$container);

				for (var i = $li.length; i--; )
				{
					if ($($li[i]).hasClass('selected'))
					{
						removeTagByIndex(i);
					}
				}

				evt.stopPropagation();
				evt.preventDefault();
			}
		}
		else if (-1 !== $.inArray(evt.keyCode, [38, 40, 13]))
		{
			evt.preventDefault();
		}
	}

	function onHolderKeyUp(evt)
	{
		var value = $.trim(_$holder.val()),
			valueLength = value.length;

		if (0 === valueLength)
		{
			_$holder.val('');

			$('li.itags-item', _$hintContainer).remove();

			_$hintDefault.show();
			_$hintContainer.show();

			return;
		}

		var $selectedHint = $('li.itags-item.selected', _$hintContainer);

		if ($('li.itags-item', _$hintContainer).length)
		{
			if (40 === evt.keyCode)
			{
				if ($selectedHint.length)
				{
					if ($selectedHint.nextAll().length)
					{
						$selectedHint.removeClass('selected');
						$('li.itags-item', _$hintContainer)
							.eq($selectedHint.prevAll().length)
							.addClass('selected');
					}
				}
				else
				{
					$('li.itags-item:first', _$hintContainer).addClass('selected');
				}

				evt.stopPropagation();
				evt.preventDefault();

				return;
			}

			if (38 === evt.keyCode)
			{
				if ($selectedHint.length)
				{
					if ($selectedHint.prevAll().length - 1 > 0)
					{
						$selectedHint.removeClass('selected');

						$('li.itags-item', _$hintContainer)
							.eq($selectedHint.prevAll().length - 2)
							.addClass('selected');
					}
				}

				evt.stopPropagation();
				evt.preventDefault();

				return;
			}
		}

		if (_options.tag_separator_pattern.test(value))
		{
			_$holder.val('');

			evt.stopPropagation();
			evt.preventDefault();

			var tags = value.split(_options.tag_separator_pattern);

			for (var tag, i = 0, l = tags.length; i<l; i++)
			{
				tag = $.trim(tags[i]);

				if (tag)
				{
					addTag(tag);
				}
			}

			return;
		}

		if (13 === evt.keyCode) // Enter
		{
			if (0 < $selectedHint.length)
			{
				var tag = $selectedHint.data('ajutor');

				_$holder.val('');

				$('li.itags-item', _$hintContainer).remove();

				_$hintDefault.show();

				addTag(tag);
			}
			else if ('' !== value)
			{
				_$holder.val('');

				$('li.itags-item', _$hintContainer).remove();

				_$hintDefault.show();

				addTag(value);
			}

			evt.stopPropagation();
			evt.preventDefault();

			return;
		}

		$('li.itags-item', _$hintContainer).remove();

		if (valueLength)
		{
			var isHintIsset = false;

			for (var i = 0, hint, l = _options.hints.length; i<l; i++)
			{
				hint = _options.hints[i];

				if (0 === hint.indexOf(value))
				{
					$('<LI class="itags-item">' + '<b>' + hint.substr(0, valueLength) + '</b>' + hint.substr(valueLength) + '</LI>')
						.hover(addOverClass, removeOverClass)
						.mousedown(function(evt)
						{
							evt.preventDefault();

							var tag = $(this).data('ajutor');

							_$holder.val('');

							$('li.itags-item', _$hintContainer).remove();

							_$hintDefault.show();

							addTag(tag);
						})
						.appendTo(_$hintContainer)
						.data('ajutor', hint);

					isHintIsset = true;
				}
			}

			if (isHintIsset)
			{
				_$hintDefault.hide();
			}
			else
			{
				_$hintDefault.show();
			}
		}
		else
		{
			_$hintDefault.show();
		}

		_$input.triggerHandler('keyup', {'value': value});
	}

	function addOverClass()
	{
		$(this).addClass('over');
	}

	function removeOverClass()
	{
		$(this).removeClass('over');
	}

	return _$input;
};

/**
 *
 * @param {Object} options
 */
jQuery.fn.itags = function(options)
{
	options = options || {};

	this.each(function()
	{
		new jQuery.itags(this, options);
	});

	return this;
};

/** @type {Object} */
jQuery.fn.itags.defaultOptions = {
	'hints': [],
	'tag_separator': ', ',
	'tag_hint': 'Введите метку и нажмите Enter&#8230;',
	'tag_separator_pattern': /,\s|,|;/g
};
